package com.androider.timememory.utils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.lang.ref.WeakReference;

import com.androider.timememory.R;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.BitmapFactory.Options;
import android.media.ThumbnailUtils;
import android.provider.MediaStore.Video.Thumbnails;


public class ImageUtil {
	
	public static Bitmap BitmapZoomClip(Bitmap image, float width, float height) {
		return BitmapZoom(BitmapClip(image, width, height), width, height);
	}
	
	public static Bitmap BitmapZoom(Bitmap image, float width, float height) {
		if(image == null) {
			return null;
		}
		
		Matrix mMatrix = new Matrix();
		mMatrix.postScale(width / image.getWidth(), height / image.getHeight());
		return Bitmap.createBitmap(image, 0, 0, image.getWidth(),
				image.getHeight(), mMatrix, true);
	}
	
	public static Bitmap BitmapClip(Bitmap image, float width, float height) {
		if(image == null) {
			return null;
		}
		
		float imgWidth = image.getWidth();
		float imgHeight = image.getHeight();
		int cut = 0;
		if (imgWidth / imgHeight > width / height) {
			cut = (int) (imgWidth - imgHeight / height * width) / 2;
			return Bitmap.createBitmap(image, (int) cut, 0,
					(int) (imgWidth - 2 * cut), (int) imgHeight);
		} else {
			cut = (int) (imgHeight - imgWidth / width * height) / 2;
			return Bitmap.createBitmap(image, 0, (int) cut, (int) imgWidth,
					(int) (imgHeight - 2 * cut));
		}
	}
	
	public static Bitmap decodeStream(InputStream is, Rect outPadding, Options opts) {
		try {
			return BitmapFactory.decodeStream(is, outPadding, opts);
		} catch (OutOfMemoryError e) {
			// TODO Auto-generated catch block
			return null;
		}
	}
	
	/**
	 * Save bitmap to file on sdcard
	 * @param path the directory to save file
	 * @param filename the filename without suffix
	 * @param mBitmap
	 * @return
	 */
	public static boolean saveBitmap(String path, String filename, Bitmap mBitmap){
		String returnfilename = "";
		if(null == mBitmap){
			return false;
		}
		
		FileUtil.createDirectory(path);
		returnfilename = path + filename + ".png";
		File f = new File(returnfilename);
		try {
			FileOutputStream fOut = new FileOutputStream(f);
			mBitmap.compress(Bitmap.CompressFormat.PNG, 80, fOut);
			fOut.flush();
			fOut.close();
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
        return true;

	}
	
	/**
	 * Get small thumbnail according to type
	 * @param context
	 * @param path
	 * @param type
	 * @return
	 */
	public static Bitmap getSmallThumbnail(Context context, String path, String type) {
		Resources res = context.getResources();
		if(type.equals(res.getString(R.string.list_type_photo))) {
			return getPhotoSmallThumbnail(path);
		} else if(type.equals(res.getString(R.string.list_type_video))) {
			return getVideoSmallThumbnail(path);
		} else {
			return null;
		}
		
	}
	
	/**
	 * Get the original bitmap of photo
	 * @param fileName
	 * @return
	 */
	public static Bitmap getOriginalPhoto(String fileName) {
		File f = new File(FileUtil.RECORD_PICTURE_DIR, fileName + ".jpg");
	      if (f.exists()) {
	          return new WeakReference<Bitmap>(BitmapFactory.decodeFile(f.getPath())).get();
	      }
	      return null;
	}
	
	public static Bitmap getThumbnail(Context context, String path, String type) {
		Resources res = context.getResources();
		if(type.equals(res.getString(R.string.list_type_photo))) {
			return getPhotoThumbnail(path);
		} else if(type.equals(res.getString(R.string.list_type_video))) {
			return getVideoThumbnail(path);
		} else {
			return null;
		}
	}
	
	
	/**
	 * Get the thumbnail bitmap of photo
	 * @param fileName
	 * @return
	 */
	public static Bitmap getPhotoThumbnail(String fileName) {
		try {
            File f = new File(FileUtil.RECORD_PICTURE_THUMBNAIL_DIR, fileName + ".png");
            if (f.exists()) {
                return new WeakReference<Bitmap>(BitmapFactory.decodeFile(f.getPath())).get();
            }
            
            String filePath = FileUtil.RECORD_PICTURE_DIR + fileName + ".jpg";
            BitmapFactory.Options opt = new BitmapFactory.Options();
            opt.inJustDecodeBounds = true;
            BitmapFactory.decodeFile(filePath, opt);
            opt.inSampleSize = computeSampleSize(opt, -1, 450 * 300);
            opt.inJustDecodeBounds = false;
            WeakReference<Bitmap> r = new WeakReference<Bitmap>(BitmapFactory.decodeFile(filePath, opt));
            saveBitmap(FileUtil.RECORD_PICTURE_THUMBNAIL_DIR, fileName, r.get());
            return r.get();
            
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
	}
	
	/**
	 * Get the small thumbnail bitmap of photo used in list
	 * @param filePath
	 * @return
	 */
    public static Bitmap getPhotoSmallThumbnail(String fileName) {
        try {
            File f = new File(FileUtil.RECORD_PICTURE_SMALL_THUMBNAIL_DIR, fileName + ".png");
            if (f.exists()) {
                return new WeakReference<Bitmap>(BitmapFactory.decodeFile(f.getPath())).get();
            }
            
            String filePath = FileUtil.RECORD_PICTURE_DIR + fileName + ".jpg";
            BitmapFactory.Options opt = new BitmapFactory.Options();
            opt.inJustDecodeBounds = true;
            BitmapFactory.decodeFile(filePath, opt);
            opt.inSampleSize = computeSampleSize(opt, -1, 150 * 150);
            opt.inJustDecodeBounds = false;
            WeakReference<Bitmap> r = new WeakReference<Bitmap>(BitmapFactory.decodeFile(filePath, opt));
            saveBitmap(FileUtil.RECORD_PICTURE_SMALL_THUMBNAIL_DIR, fileName, r.get());
            return r.get();
            
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    
    public static int computeSampleSize(BitmapFactory.Options options,
            int minSideLength, int maxNumOfPixels) {
        int initialSize = computeInitialSampleSize(options, minSideLength,
                maxNumOfPixels);

        int roundedSize;
        if (initialSize <= 8) {
            roundedSize = 1;
            while (roundedSize < initialSize) {
                roundedSize <<= 1;
            }
        } else {
            roundedSize = (initialSize + 7) / 8 * 8;
        }

        return roundedSize;
    }

    private static int computeInitialSampleSize(BitmapFactory.Options options,
            int minSideLength, int maxNumOfPixels) {
        double w = options.outWidth;
        double h = options.outHeight;

        int lowerBound = (maxNumOfPixels == -1) ? 1 :
                (int) Math.ceil(Math.sqrt(w * h / maxNumOfPixels));
        int upperBound = (minSideLength == -1) ? 128 :
                (int) Math.min(Math.floor(w / minSideLength),
                Math.floor(h / minSideLength));

        if (upperBound < lowerBound) {
            // return the larger one when there is no overlapping zone.
            return lowerBound;
        }

        if ((maxNumOfPixels == -1) &&
                (minSideLength == -1)) {
            return 1;
        } else if (minSideLength == -1) {
            return lowerBound;
        } else {
            return upperBound;
        }
    }
    
    /**
     * Create video thumbnail
     * @param videoPath
     * @return
     */
    public static Bitmap createVideoThumbnail(String videoPath) {
    	Bitmap mBitmap = ThumbnailUtils.createVideoThumbnail(videoPath, Thumbnails.MINI_KIND);
        return  new WeakReference<Bitmap>(ThumbnailUtils.extractThumbnail(mBitmap, 480, 320, ThumbnailUtils.OPTIONS_RECYCLE_INPUT)).get();
    }
    
    /**
     * Get the thumbnail bitmap of video
     * @param fileName
     * @return
     */
    public static Bitmap getVideoThumbnail(String path) {
    	String fileName = FileUtil.getFileNameFromPath(path);
    	try {
            File f = new File(FileUtil.RECORD_VIDEO_THUMBNAIL_DIR, fileName + ".png");
            if (f.exists()) {
                return new WeakReference<Bitmap>(BitmapFactory.decodeFile(f.getPath())).get();
            }
            
            return ImageUtil.createVideoThumbnail(path);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    
    /**
	 * Get the small thumbnail bitmap of video used in list
	 * @param filePath
	 * @return
	 */
    public static Bitmap getVideoSmallThumbnail(String path) {
    	String fileName = FileUtil.getFileNameFromPath(path);
        try {
            File f = new File(FileUtil.RECORD_VIDEO_SMALL_THUMBNAIL_DIR, fileName + ".png");
            if (f.exists()) {
                return new WeakReference<Bitmap>(BitmapFactory.decodeFile(f.getPath())).get();
            }
            
            Bitmap mBitmap = ThumbnailUtils.createVideoThumbnail(path, Thumbnails.MINI_KIND);
            mBitmap = ThumbnailUtils.extractThumbnail(mBitmap, 170, 130, ThumbnailUtils.OPTIONS_RECYCLE_INPUT);
            WeakReference<Bitmap> r = new WeakReference<Bitmap>(mBitmap);
            saveBitmap(FileUtil.RECORD_VIDEO_SMALL_THUMBNAIL_DIR, fileName, r.get());
            return  r.get();

        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
	
	public static Bitmap readBitmap(String path) {
		BitmapFactory.Options opt = new BitmapFactory.Options();  
		opt.inPreferredConfig = Bitmap.Config.RGB_565;   
		opt.inPurgeable = true;  
		opt.inInputShareable = true;
		File file = new File(path);
		if(!file.exists()) return null;
		try {
			InputStream i = new FileInputStream(file);
			return new WeakReference<Bitmap>(ImageUtil.decodeStream(i,null,opt)).get();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			return null;
		}
    }
}
